import math
from operator import index
from ..db import mssql
import socket
import threading
import time

class TModbusTcpClient:
    def __init__(self) -> None:
        self.host = ""
        self.port = 502
        self.tasks = {}
        self.taskList =[]
        self.registers = {}
        self.info = {}
        self.skt = None
        self.taskIndex =0
        self.txNo =0


        self.timeStart=0
        self.timeEnd =0
        self.startTime = 0
    def isActive(self):
        res= False
        try:
            flag = self.skt!=None and (not self.skt._closed)
            res = flag
        except Exception as er:
            print(er)
        return res
    def connectModbusTcp(self):
        try:
            self.startTime = time.time()
            isActived = self.isActive()
            if isActived:
                return

            print('connect modbus tcp :'+ self.host+":"+str(self.port))
            address = (self.host , self.port)
            self.skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.skt.settimeout(5)
            self.skt.connect(address) 
            self.taskIndex = -1

            while 1>0:
                try:
                    task = self.getNextTask()
                    if task!=None:
                        self.readTaskRegisters(task)
                except Exception as err:
                    print(err )


        except Exception as er:
            print(er)
    def connectModbusTcpAsymc(self):
        try:
            if self.startTime ==0 :
                execThread = threading.Thread(target=self.connectModbusTcp)
                execThread.setDaemon(True)
                execThread.start()
        except Exception as er:
            print(er)

    def hasTempTask(self):
        res = False
        try:
            res = False
        except Exception as er:
            print(er)
        return res
    def getNextTask(self):
        res = None
        try:
            flag = self.hasTempTask()
            if flag:
                res = self.taskList[0]
            else:
                self.taskIndex = self.taskIndex + 1
                if self.taskIndex == 0 :
                    self.timeStart = time.time()
                if self.taskIndex >= len(self.taskList):
                    self.timeEnd = time.time()

                    delay = self.timeEnd - self.timeStart;
                    self.timeStart = time.time()
                    print('------------ time: '+str(delay)+' ---------------------')

                    self.taskIndex =0
                if len(self.taskList)>0:
                    res = self.taskList[self.taskIndex]
        except Exception as er:
            print('------------ index --------------')
            print(er)
        #print('taskId:'+str(res["taskId"]))
        return res
    def readTaskRegisters(self, task):
        try:
            timeNow = time.time()
            cmdBytes = self.getTaskCmdBytes(task)
            self.skt.send(cmdBytes) 
            time.sleep(0.01)
            recBytes = self.skt.recv(1024) 
            flag =  len(recBytes)>9 #and recBytes[1] == cmdBytes[1]
            if flag :
                offset = 8
                recDataLen = recBytes[offset]
                offset = offset + 1
                flag = len(recBytes)-9 == recDataLen 
                if flag :
                    index =0   
                    regNum = task["regNum"]     
                    unitId = task["unitId"]     
                    funCode = task["funCode"]     
                    devCode = task["devCode"]     
                                 
                    while index<regNum:
                        try:
                            regAddr = task["regAddr"] + index      
                            regKey = devCode + '_'+ str(unitId) +'_'+ str(funCode) + '_'+ str(regAddr)  
                            reg = self.registers[regKey]; 
                            reg["time"] = timeNow  
                            if funCode==1 or funCode ==2 :
                                byteIndex = math.floor(index * 0.125) 
                                bitIndex = index % 8 
                                byteVal = recBytes[offset + byteIndex]
                                val = (byteVal >> bitIndex) & 0x01                            
                                reg["bit"] = val
                                #print(str(regAddr) +'/'+ str(index) +':'+ str(regNum) +'-'+str(byteIndex) +'-'+str(bitIndex))
                            elif funCode==3 or funCode ==4 :
                                try:
                                    pos = offset + index*2 
                                    h = recBytes[pos]
                                    l = recBytes[pos+1]
                                    reg["h"] = h 
                                    reg["w"] = l
                                except Exception as eee:
                                    print(eee);
                            #print(str(regAddr) +'/'+ str(index) +':'+ str(pos) +'-'+str(pos+1) )
                        except Exception as e1:
                            print(e1)
                        index = index + 1 
                    print('task:'+ str(task["unitId"])+"-"+str(task["taskId"])+"-"+str(task["regNum"])+"-"+str(index))
            else:
                print('**********')
                print(cmdBytes)
                print(recBytes)
                print('**********')
        except Exception as er:
            print(er)
    def getTaskCmdBytes(self, task):
        res =None
        try: 
            self.txNo = self.txNo +1
            if self.txNo>=0xfff0:
                self.txNo =1
            tranBytes = int.to_bytes( self.txNo , 2 , byteorder='big' ) 
            regAddrBytes = int.to_bytes( task["regAddr"] , 2 , byteorder='big' ) 
            regNumBytes = int.to_bytes( task["regNum"] , 2 , byteorder='big' )  
            res = bytearray(
                [
                    tranBytes[0],tranBytes[1] ,
                    #0x00,0x00,
                    0x00,0x00,
                    0x00,0x06,
                    task["unitId"], task["funCode"],
                    regAddrBytes[0],regAddrBytes[1] ,
                    regNumBytes[0],regNumBytes[1] ,
                ]
            )
        except Exception as er:
            print(er) 
        return res
class TModbusTcp :
    def __init__(self) -> None:
        self.clients = []
    def startClients(self):
        try:
            for client in self.clients:
                client.connectModbusTcpAsymc()
        except Exception as er:
            print(er)
    def routerHandlerStartClients(self, result , request , router):
        try:
            self.startClients();
            result["status"] = 1;
            result["datas"] ={};
        except Exception as er:
            print(er)
    def routerHandlerGetRegisters(self, result , request , router):
        try:            
            ps = router.getRequestParams(request)
            devCode = ps["devCode"]
            dev = None
            for client in self.clients:
                if client.info["devCode"] == devCode :
                    dev = client
                    break
            if dev == None:
                result["status"] = -1
                result["error"] = "devCode is error"
            else:            
                result["status"] = 1
                result["datas"] = dev.registers
        except Exception as er:
            print(er)



objs = mssql.mssql.connections["modbusTcp"].queryBySqlKey("modubusObj", None)
modbusTcp = TModbusTcp()
devs = objs[0]
tasks = objs[1]
registers = objs[2]

 

for dev in devs:
    client = TModbusTcpClient()
    client.host = dev['devHost']
    client.port = dev['devPort']
    client.info = dev 
    modbusTcp.clients.append(client)
    for t in tasks:
        if t['devId'] == dev['devId']:
            client.tasks[t['taskId']] = t
            t['regs'] =[]
            for r in registers:
                if r['taskId'] == t['taskId']:
                    t['regs'].append(r)
    client.taskList = list(client.tasks.values())
    for r in registers:
        if r['devId'] == dev['devId']:
            client.registers[r['regKey']] = r
print(modbusTcp)
#modbusTcp.startClients()


            